
 nam OS-9 Level I V1.2 kernal, part 1
 ttl System Type definitions

 use defsfile

 ifeq (CPUType-GIMIX)*(CPUType-EXORSR)
 opt l
 else
 opt -l
 endc

 ttl Names & tables
 opt -c
 page

************************************************************
*                                                          *
*           OS-9 Level I V1.2 - Kernal, part 1             *
*                                                          *
************************************************************

* Copyright 1980 by Motorola, Inc., and Microware Systems Corp.,
* Reproduced Under License

*
* This source code is the proprietary confidential property of
* Microware Systems Corporation, and is provided to licensee
* solely  for documentation and educational purposes. Reproduction,
* publication, or distribution in any form to any party other than 
* the licensee is strictly prohibited!!
*

*****
*
*  Module Header
*
Type set SYSTM+OBJCT
Revs set REENT+1
 mod OS9End,OS9Nam,Type,Revs,COLD,0
OS9Nam fcs /OS9p1/
 fcb 12 Edition number

*************************
*    Edition History
*
* Ed.  8 - Beginning of history  (V1.1 final version)
*
* Ed.  9 - First V1.2 version minor cosmetic changes
*          Ed byte immediately following module name
*          Version ID all same length                  WGP  11/25/82
*
* Ed. 10 - SetSVC now checks service no. for validity
*          SetPRC checks for zero data area size       WGP  12/20/82
*
* Ed. 11 - Parse name system call made compatible w/LII
*                                                      ???  ??/??/82
*
* Ed. 12 - CNAM change made at RETCS1 to save one byte of code
*          S09 cpu datinit changed to save one byte of code
*          These were to allow S09 version to fit in $800
*                                                      WGP  01/10/83

*********
* Version Id
*
 ifeq CPUType-EXORSR
 fcc / Exor / Version name
RamLimit set $E000
 endc
 ifeq CPUType-MM19
 fcc / MM19 / Version name
RamLimit set $E800
 endc
 ifeq CPUType-GIMIX
 fcc / Gmx  / Version name
RamLimit set $E000
 endc
 ifeq CPUType-SWTC
 fcc /Swtpc / Version name
RamLimit set $E000
 endc
 ifeq CPUType-S09
 fcc /SwtMem/ Version name
RamLimit set $E000
 endc
 ifeq CPUType-SSB
 fcc /Smoke / Version name
RamLimit set $E800
 endc
 ifeq CPUType-PERCOM
 fcc /Percom/ Version name
RamLimit set $E800
 endc
 ifeq CPUType-CMS9609
 fcc / CMS  / Version name
RamLimit set $E000
 endc
 ifeq CPUType-CMS9619
 fcc / CMS  / Version name
RamLimit set $F000
 endc
 ifeq CPUType-HELIX
 fcc /Helix /
RamLimit set $E000
 endc
 ifeq CPUType-ELEKTRA
 fcc /Elekt / AAA chicago cpu
RamLimit set $E000
 endc
 ifeq CPUType-DIGALOG
 fcc /Diglog/ Digalog cpu
RamLimit set $E000
 endc
 ifeq CPUType-SAT96
 fcc /SAT96 / Sat-96 board
RamLimit set $E600
 endc

CNFSTR fcs /Init/ Configuration module name
OS9STR fcs /OS9p2/ Kernal, part 2 name
 page
*****
*
* System Service Routine Table
*
SVCTBL equ *
 fcb F$LINK
 fdb LINK-*-2
 fcb F$FORK
 fdb FORK-*-2
 fcb F$Chain
 fdb USRCHN-*-2
 fcb F$Chain+$80
 fdb SYSCHN-*-2
 fcb F$PrsNam
 fdb PNAM-*-2
 fcb F$CmpNam
 fdb CNAM-*-2
 fcb F$SchBit
 fdb SBIT-*-2
 fcb F$AllBit
 fdb ABIT-*-2
 fcb F$DelBit
 fdb DBIT-*-2
 fcb F$CRC
 fdb CRCGen-*-2
 fcb F$SRqMem+$80
 fdb SRQMEM-*-2
 fcb F$SRtMem+$80
 fdb SRTMEM-*-2
 fcb F$AProc+$80
 fdb APRC-*-2
 fcb F$NProc+$80
 fdb NXTPRC-*-2
 fcb F$VModul+$80
 fdb VMOD-*-2
 fcb F$SSVC
 fdb SSVC-*-2
 fcb $80



 ttl COLD Start
 page
*
* Clear System Memory, Skipping First 32 Bytes
*
LORAM set $20
HIRAM set $300
RAMMSK set $F0 Initial bit map mask
COLD ldx #LORAM Set ptr
 ldy #HIRAM-LORAM Set byte count
 clra CLEAR D
 clrb
COLD05 std ,X++ Clear two bytes
 leay -2,Y Count down
 bne COLD05
 inca ONE Page for direct page
 std D.FMBM Set free memory bit map
 addb #BMAPSZ Add map size
 std D.FMBM+2
 addb #2 Reserve i/o routine entry
 std D.SysDis Set system service request table
 addb #SVCTSZ+2 Add table size
 std D.UsrDis Set user service request table
 clrb SET Module directory address
 inca
 std D.ModDir Set module directory address
 stx D.ModDir+2 Set end
 leas $100,X get initial stack
*
* Find End Of Ram
*
COLD10 leay 0,X Copy current ptr
 ldd 0,Y Get current value
 ldx #$00FF Get bit pattern
 stx 0,Y Store it
 cmpx 0,Y Is it there?
 bne COLD15 If not, end of ram
 ldx #$FF00 Try a different pattern
 stx 0,Y Store it
 cmpx 0,Y Did it take?
 bne COLD15 If not, eor
 std 0,Y Replace current value
 leax 256,Y Try next page
 cmpx #RamLimit
 bcs COLD10 Branch if more
 leay 0,X Copy end-of-ram ptr
COLD15 leax 0,Y Copy eor ptr

 ifeq CPUType-EXORSR
*** >>> Patch For Exorciser Environment <<< ***
*
 leax NMI,pcr
 stx $FFFC
 leax SWIRQ,pcr
 stx $FFFA
 leax IRQ,PCR get irq vector
 stx $FFF8 set hardware vector
 leax SWI2RQ,PCR get swi2 vector
 stx $FFF4 set hardware vector
 leax SWI3RQ,PCR get swi3 vector
 stx $FFF2 set hardware vector
EndRAM equ $A50 This must be greater than the size
* of ctlrmod+bootmod+os9p2+*
 leax -EndRAM,PCR get artificial end-of-ram
 stx D.BtLo
 stx D.BtHi
*
*** >>> End Of Exorciser Patch <<< ***
 endc

 stx D.MLIM Set memory limit
*
* Search Memory For Modules, Build Module Directory
*
COLD20 lbsr VALMOD Look for valid module
 bcs COLD30 Branch if bad module
 ldd M$SIZE,X Get module size
 leax D,X Skip module
 bra COLD35
COLD30 cmpb #E$KwnMod Is it known module
 beq COLD40 Branch on first duplicate
 leax 1,X Try next location
COLD35 bne COLD20
COLD40 leay SYSVEC,PCR Get interrupt entries
 leax ROMEnd,PCR get vector offset
 pshs X save it
 ldx #D.SWI3 Get vector address
COLD45 ldd ,Y++ get vector
 addd 0,S add offset
 std ,X++ init dp vector
 cmpx #D.NMI end of dp vectors?
 bls COLD45 branch if not
 leas 2,S return scratch
 leax USRIRQ,PCR Get user interrupt routine
 stx D.UsrIRQ
 leax USRREQ,PCR Get user service routine
 stx D.UsrSVC
 leax SYSIRQ,PCR Get system interrupt routine
 stx D.SysIRQ
 stx D.SvcIRQ Set interrupts to system state
 leax SYSREQ,PCR Get system service routine
 stx D.SysSVC
 stx D.SWI2 Set service to system state
 leax IOPOLL,PCR Set irq polling routine
 stx D.POLL
*
* Initialize Service Routine Dispatch Table
*
 leay SVCTBL,PCR Get ptr to service routine table
 lbsr SETSVC Set service table entries
 lda #SYSTM Get system type module
 leax CNFSTR,PCR Get initial module name ptr
 OS9 F$LINK Link to configuration module
 lbcs COLD Retry if error
 stu D.Init Save ptr
 ldd MAXMEM+1,U Get memory limit
 clrb ROUND Down
 cmpd D.MLIM Does ram go that high?
 bcc COLD50 Branch if not
 std D.MLIM Set given memory limit
COLD50 ldx D.FMBM Get bit map ptr
 ldb #RAMMSK Get initial mask
 stb 0,X
 clra GET Beginning page number
 ldb D.MLIM
 negb GET Page count
 tfr D,Y
 negb GET Page number
 lbsr ALOCAT
 leax OS9STR,PCR
 lda #SYSTM+OBJCT Get object type
 OS9 F$LINK
 lbcs COLD
 jmp 0,Y Let os9 part two finish

 ttl INTERRUPT Service handlers
 page
*****
*
*  Swi3 Interrupt Routine
*
SWI3RQ jmp [D.SWI3] Go thru page zero vector



*****
*
*  Swi2 Interrupt Routine
*
SWI2RQ jmp [D.SWI2] Go thru page zero vector



*****
*
*  Firq Interrupt Handler
*
FIRQ jmp [D.FIRQ] Go thru page zero vector



*****
*
*  Irq Interrupt Routine
*
IRQ jmp [D.IRQ] Go thru page zero vector



*****
*
*  Swi Interrupt Routine
*
SWIRQ jmp [D.SWI] Go thru page zero vector



*****
*
*  Nmi Interrupt Routine
*
NMI jmp [D.NMI] Go thru page zero vector
 page
*****
*
*  Swi3 Handler
*
SWI3HN pshs B,X,PC Save registers
 ldb #P$SWI3 Use swi3 vector
 bra SWIH10



*****
*
*  Swi2 Handler
*
SWI2HN pshs B,X,PC Save registers
 ldb #P$SWI2 Use swi2 vector
 bra SWIH10



*****
*
*  Firq Handler
*
FIRQHN rti



*****
*
*  Irq Handler
*
IRQHN jmp [D.SvcIRQ] Go to interrupt service



*****
*
*  Swi Handler
*
SWIHN pshs B,X,PC Save registers
 ldb #P$SWI Use swi vector
SWIH10 ldx >D.PROC Get process descriptor ptr
 ldx B,X Get entry point address
 stx 3,S Save it
 puls B,X,PC Restore registers & jump



*****
*
*  Nmi Handler
*
NMIHN equ FIRQHN
 page
*****
*
*  Interrupt Service Routine Usrirq
*
* Handles Irq While In User State
*
USRIRQ leay <USRI10,PCR Get post-switch routine
SWITCH clra SET Direct page
 tfr A,DP
 ldx D.PROC Get process
 ldd D.SysSVC Get system request routine
 std D.SWI2
 ldd D.SysIRQ Get system irq routine
 std D.SvcIRQ
 leau 0,S Copy user stack ptr
 stu P$SP,X
 lda P$State,X Set system state
 ora #SysState
 sta P$State,X
 jmp 0,Y Go to post-switch routine
USRI10 jsr [D.POLL] Call irq polling routine
 bcc USRI20 branch if interrupt identified
 ldb R$CC,S get condition codes
 orb #IRQMask set interrupt mask
 stb R$CC,S update condition codes
USRI20 lbra USRRET



*****
*
*  Interrupt Routine Sysirq
*
* Handles Irq While In System State
*
SYSIRQ clra clear direct page
 tfr A,DP
 jsr [D.POLL] Call irq polling
 bcc SYSI10 branch if interrupt identified
 ldb R$CC,S get condition codes
 orb #IRQMask set interrupt mask
 stb R$CC,S update condition codes
SYSI10 rti



*****
*
*  Interrupt Polling Default
*
IOPOLL comb set carry
 rts
 page
*****
*
*  Clock Tick Routine
*
* Wake Sleeping Processes
*
TICK ldx D.SProcQ Get sleeping queue ptr
 beq SLICE Branch if none
 lda P$State,X Get process status
 bita #TimSleep Is it in timed sleep?
 beq SLICE Branch if not
 ldu P$SP,X Get stack ptr
 ldd R$X,U Get tick count
 subd #1 Count down
 std R$X,U Update tick count
 bne SLICE Branch if ticks left
TICK10 ldu P$Queue,X Get next process ptr
 bsr ACTPRC Activate process
 leax 0,U Copy process ptr
 beq TICK20 Branch if end of queue
 lda P$State,X Get process status
 bita #TimSleep In timed sleep?
 beq TICK20 Branch if not
 ldu P$SP,X Get stack ptr
 ldd R$X,U Get tick count
 beq TICK10 Branch if time
TICK20 stx D.SProcQ Update sleep queue ptr
*
* Update Time Slice counter
*
SLICE dec D.Slice Count tick
 bne SLIC10 Branch if slice not over
 lda D.TSlice Get ticks/time-slice
 sta D.Slice Reset slice tick count
*
* If Process not in System State, Give up Time-Slice
*
 ldx D.PROC Get current process ptr
 beq SLIC10 Branch if none
 lda P$State,X Get status
 ora #TIMOUT Set time-out flag
 sta P$State,X Update process status
 bpl SLIC20 Branch if user state
SLIC10 rti
SLIC20 leay USRRET,PCR Set transfer ptr
 bra SWITCH Switch to system state
 page
*****
*
*  Subroutine Actprc
*
* Put Process In Active Process Queue
*
APRC ldx R$X,U
ACTPRC pshs Y,U Save registers
*
* Age Active Processes
*
 ldu #D.AProcQ-P$Queue Fake process ptr
 bra ACTP20
ACTP10 ldb P$AGE,U Get age
 incb
 beq ACTP20 Branch if highest
 stb P$AGE,U
ACTP20 ldu P$Queue,U Get next process
 bne ACTP10 Branch if more
*
* Sort New Process Into Queue
*
 ldu #D.AProcQ-P$Queue Fake process ptr
 lda P$Prior,X Get process priority/age
 sta P$AGE,X Set age to priority
 orcc #IRQMask+FIRQMask Set interrupt masks
ACTP30 leay 0,U Copy ptr to this process
 ldu P$Queue,U Get ptr to next process
 beq ACTP40 Branch if no more
 cmpa P$AGE,U Who has bigger priority?
 bls ACTP30 Branch if queue process
ACTP40 stu P$Queue,X Insert into list
 stx P$Queue,Y
 clrb CLEAR Carry
 puls Y,U,PC
 page
*****
*
*  Subroutine Usrreq
*
* User Service Request Handling Routine
*
USRREQ leay <USRR10,PCR Get post-switch routine
 orcc #IRQMask+FIRQMask Set interrupt masks
 lbra SWITCH Switch to system state
USRR10 andcc #$FF-IRQMask-FIRQMask Clear interrupt masks
 ldy D.UsrDis Get user service routine table
 bsr DISPCH Go do request
USRRET ldx D.PROC Get process ptr
 beq NXTPRC Branch if none
 orcc #IRQMask+FIRQMask Set interrupt masks
 ldb P$State,X Clear system state
 andb #$FF-SysState
 stb P$State,X Update status
 bitb #TIMOUT Is time-slice over?
 beq CURPRC Branch if not
 andb #$FF-TIMOUT Clear time-out flag
 stb P$State,X Update status
USRR20 bsr ACTPRC Put in active queue
 bra NXTPRC Start next process



*****
*
*  Subroutine Sysreq
*
SYSREQ clra clear direct page
 tfr A,DP
 leau 0,S Copy stack ptr
 ldy D.SysDis Get system service routine table
 bsr DISPCH Call service routine
 rti
 page
*****
*
*  Subroutine Dispch
*
* Service Routine Dispatch
*
DISPCH pshs U Save register ptr
*
* Get Service Request Code
*
 ldx R$PC,U Get program counter
 ldb ,X+ Get service code
 stx R$PC,U Update program counter
*
* Get Service Routine Address
*
 aslb SHIFT For two byte table entries
 bcc DISP10 Branch if not i/o
 rorb RE-ADJUST Byte
 ldx -2,Y Get i/o routine
 bra DISP20
DISP10 cmpb #SVCTSZ Code in range?
 bcc BADSVC
 ldx B,Y Get routine address
 beq BADSVC Branch if none
DISP20 jsr 0,X Call routine
*
* Return Condition Codes To Caller
*
DISP25 puls U Retrieve register ptr
 tfr CC,A Copy condition codes
 bcc DISP30 Branch if no error
 stb R$B,U Return error code
DISP30 ldb R$CC,U Get condition codes
 andb #$F0 Clear n, z, v, c
 stb R$CC,U Save it
 anda #$0F Clear e, f, h, i
 ora R$CC,U Return conditions
 sta R$CC,U
 rts

BADSVC comb SET Carry
 ldb #E$UnkSvc Unknown service code
 bra DISP25
 page
*****
*
*  Routine Nxtprc
*
* Starts next Process in Active Queue
* If no Active Processes, Wait for one
*
NXTOUT ldb P$State,X Get process status
 orb #SysState Set system state
 stb P$State,X Update status
 ldb P$Signal,X Return fatal signal
 andcc #$FF-IRQMask-FIRQMask Clear interrupt masks
 OS9 F$EXIT Terminate process
NXTPRC clra
 clrb
 std D.PROC Clear current process
 bra NXTP06
*
* Loop until there is a Process in the Active Queue
*
NXTP04 cwai #$FF-IRQMask-FIRQMask Clear interrupt masks & wait
NXTP06 orcc #IRQMask+FIRQMask Set interrupt masks
 ldx D.AProcQ Get first process in active queue
 beq NXTP04 Branch if none
*
* Remove Process from Active Queue
*
 ldd P$Queue,X Get next process ptr
 std D.AProcQ Remove first from active queue
 stx D.PROC Set current process
 lds P$SP,X Get stack ptr
*
* Check Process Status, check for Signal pending
*
CURPRC ldb P$State,X Is process in system state?
 bmi NXTP30 Branch if so
 bitb #CONDEM Is process condemmed?
 bne NXTOUT Branch if so
 ldb P$Signal,X Is a signal waiting?
 beq NXTP20 Branch if not
 decb Wake-up Signal?
 beq NXTP10 Branch if so
*
* Signal is pending; If an Intercept has been set
* Build an Interrupt Stack for User
*
 ldu P$SigVec,X Get intercept vector
 beq NXTOUT Branch if none
 ldy P$SigDat,X Get intercept data address
 ldd R$Y,S Get user y register
 pshs D,Y,U Build partial stack
 ldu R$X+6,S Get user x register
 lda P$Signal,X Get signal
 ldb R$DP+6,S Get direct page
 tfr D,Y Copy registers
 ldd R$CC+6,S Get registers
 pshs D,Y,U Complete stack
 clrb
NXTP10 stb P$Signal,X Clear signal
*
* Switch to User State
*
NXTP20 ldd P$SWI2,X Get user service request
 std D.SWI2
 ldd D.UsrIRQ Get user irq
 std D.SvcIRQ
NXTP30 rti Start next process
 page
*****
*
*  Subroutine Link
*
* Search Module Directory & Return Module Address
*
* Input: U = Register Package
* Output: Cc = Carry Set If Not Found
* Local: None
* Global: D.ModDir
*
LINK pshs U Save register package
 ldd R$D,U Get revision, type
 ldx R$X,U Get name ptr
 lbsr FMODUL Search directory
 bcc LINK10
 ldb #E$MNF Err: link non-existing module
 bra LINKXit
LINK10 ldy 0,U Get module address
 ldb M$REVS,Y get attributes/revision
 bitb #REENT is this sharable
 bne LINK20 branch if so
 tst 2,U is it in use?
 beq LINK20 branch if not
 comb set carry
 ldb #E$ModBsy err: module busy
 bra LINKXit
LINK20 inc 2,U count use
 ldu 0,S Get register ptr
 stx R$X,U
 sty R$U,U
 ldd M$TYPE,Y Get type/lang & attr/revs
 std R$D,U
 ldd M$EXEC,Y Get execution offset
 leax D,Y Make entry ptr
 stx R$Y,U Return it to user
LINKXit puls U,PC



*****
*
*  Subroutine Valmod
*
* Validate Module
*
VMOD pshs U Save register ptr
 ldx R$X,U Get new module ptr
 bsr VALMOD Validate module
 puls Y Retrieve register ptr
 stu R$U,Y Return directory entry
VMOD10 rts

VALMOD bsr IDCHK Check sync & chksum
 bcs VALM40 Branch if not module
 lda M$TYPE,X Get module type
 pshs A,X Save module type & ptr
 ldd M$NAME,X Get name ptr
 leax D,X
 puls A Retrieve type
 lbsr FMODUL Search directory
 puls X Retrieve module ptr
 bcs VALM10 Branch if not found
 ldb #E$KwnMod Get known module error code
 cmpx 0,U Is it same module?
 beq BADVAL Branch if so
 lda M$REVS,X Get new revision level
 anda #Revsmask
 pshs A Save it
 ldy 0,U Get old module ptr
 lda M$REVS,Y Get old revision level
 anda #Revsmask
 cmpa ,S+ Which is higher?
 bcc BADVAL Branch if old
 pshs X,Y Save registers
 ldb 2,U module in use?
 bne VALM15 branch if so
 ldx 0,U Get module ptr
 cmpx D.BTLO Is it rom/system module?
 bcc VALM15 Branch if so
 ldd M$SIZE,X
 addd #$FF
 tfr A,B
 clra
 tfr D,Y
 ldb 0,U
 ldx D.FMBM
 OS9 F$DelBit Clear bit map
 clr 2,U
VALM15 puls X,Y
VALM20 stx 0,U Install new module
VALM30 clrb CLEAR Carry
VALM40 rts
VALM10 leay 0,U Free directory entry?
 bne VALM20 Branch if so
 ldb #E$DirFul Err: directory full
BADVAL coma SET Carry
 rts

IDCHK ldd 0,X Get first two bytes
 cmpd #M$ID12 Check them
 bne IDCH10 Branch if not module
 leay 8,X Get header end ptr
 bsr PARITY Check header parity
 bcc IDCH30 Branch if good
IDCH10 comb SET Carry
 ldb #E$BMID Err: illegal id block
IDCH20 rts
IDCH30 pshs X Save module ptr
 ldy M$SIZE,X Get module size
 bsr CRCCHK Check crc code
 puls X,PC



*****
*
*  Subroutine Parity
*
* Check Vertical Parity
*
PARITY pshs X,Y Save registers
 clra
PARI10 eora ,X+ Add parity of next byte
 cmpx 2,S Done?
 bls PARI10 Branch if not
 cmpa #$FF Parity good?
 puls X,Y,PC



*****
*
*  Subroutine Crcchk
*
* Check Module Crc
*
CRCCHK ldd #$FFFF
 pshs D Init crc register
 pshs D
 leau 1,S Get crc register ptr
CRCC10 lda ,X+ Get next byte
 bsr CRCCAL Calculate crc
 leay -1,Y count byte
 bne CRCC10 branch if more
 clr -1,U Clear msb-1
 lda 0,U Get crc
 cmpa #$80 Is it good?
 bne CRCC20 Branch if not
 ldd 1,U Get crc
 cmpd #$0FE3 Is it good?
 beq CRCC30 Branch if so
CRCC20 comb SET Carry
 ldb #E$BMCRC Err: bad crc
CRCC30 puls X,Y,PC



*****
*
*  Subroutine Crcgen
*
* Generate Crc
*
CRCGen ldx R$X,U get data ptr
 ldy R$Y,U get byte count
 beq CRCGen20 branch if none
 ldu R$U,U get crc ptr
CRCGen10 lda ,X+ get next data byte
 bsr CRCCAL update crc
 leay -1,Y count byte
 bne CRCGen10 branch if more
CRCGen20 clrb clear carry
 rts



*****
*
*  Subroutine Crccal
*
* Calculate Next Crc Value
*
CRCCAL eora 0,U Add crc msb
 pshs A save it
 ldd 1,U Get crc mid & low
 std 0,U Shift to high & mid
 clra
 ldb 0,S Get old msb
 lslb SHIFT D
 rola
 eora 1,U Add old lsb
 std 1,U Set crc mid & low
 clrb
 lda 0,S Get old msb
 lsra SHIFT D
 rorb
 lsra SHIFT D
 rorb
 eora 1,U Add new mid
 eorb 2,U Add new low
 std 1,U Set crc mid & low
 lda 0,S Get old msb
 lsla
 eora 0,S Add old msb
 sta 0,S
 lsla
 lsla
 eora 0,S Add altered msb
 sta 0,S
 lsla
 lsla
 lsla
 lsla
 eora ,S+ Add altered msb
 bpl CRCC99
 ldd #$8021
 eora 0,U
 sta 0,U
 eorb 2,U
 stb 2,U
CRCC99 rts



*****
*
*  Subroutine Fmodul
*
* Search Directory For Module
*
* Input: A = Type
*        X = Name String Ptr
* Output: U = Directory Entry Address
*         Cc = Carry Set If Not Found
* Local: None
* Global: D.ModDir

FMODUL ldu #0 Return zero if not found
 tfr A,B Copy type
 anda #TypeMask Get desired type
 andb #LangMask Get desired language
 pshs D,X,Y,U Save registers
 bsr SKIPSP Skip leading spaces
 cmpa #'/ Is there leading '/'
 beq FMOD35
 lbsr PRSNAM Parse name
 bcs FMOD40 Branch if bad name
 ldu D.ModDir Get module directory ptr
FMOD10 pshs B,Y,U Save count, end-of-name, & directory
 ldu 0,U Get module ptr
 beq FMOD20 Branch if not used
 ldd M$NAME,U Get name offset
 leay D,U Get name ptr
 ldb 0,S Get character count
 lbsr CHKNAM Compare names
 bcs FMOD30 Branch if different
 lda 5,S Get desired type
 beq FMOD14 Branch if any
 eora M$TYPE,U Get type difference
 anda #TypeMask
 bne FMOD30 Branch if different
FMOD14 lda 6,S Get desired language
 beq FMOD16 Branch if any
 eora M$TYPE,U Get language difference
 anda #LangMask
 bne FMOD30 Branch if different
FMOD16 puls B,X,U Retrieve registers
 stu 6,S Return directory entry
 bsr SKIPSP Skip spaces
 stx 2,S Return updated ptr
 clra CLEAR Carry
 bra FMOD40
FMOD20 ldd 11,S Free entry found?
 bne FMOD30 Branch if so
 ldd 3,S Return this entry
 std 11,S
FMOD30 puls B,Y,U Retrieve registers
 leau 4,U Move to next entry
 cmpu D.ModDir+2 End of directory?
 bcs FMOD10 Branch if not
FMOD35 comb SET Carry
FMOD40 puls D,X,Y,U,PC

SKIPSP lda #'  get space
SKIP10 cmpa ,X+ Is there a space
 beq SKIP10
 lda ,-X Get not space
 rts
 page
*****
*
*  Subroutine Fork
*
* Creates New Child Process
*
FORK ldx D.PrcDBT Get process block ptr
 OS9 F$ALL64 Get new process descriptor
 bcs PRCFUL Branch if none left
 ldx D.PROC Get parent process ptr
 pshs X Save parent process ptr
 ldd P$USER,X Copy user index
 std P$USER,Y
 lda P$Prior,X Copy priority
 clrb CLEAR Age
 std P$Prior,Y
 ldb #SysState Get system state flag
 stb P$State,Y Set infant state
 sty D.PROC Make child current process
*
* Pass I/O Defaults & Paths 0, 1, And 2
*    From Parent To Child
*
 leax P$DIO,X Get parent path ptr
 leay P$DIO,Y Get child path ptr
 ldb #DefIOSiz Get byte count
FORK10 lda ,X+ Get parent byte
 sta ,Y+ Pass to child
 decb COUNT Down
 bne FORK10 Branch if more
 ldb #3 Get number of paths
FORK20 lda ,X+ Get path number
 OS9 I$DUP Duplicate path
 bcc FORK25
 clra CLEAR Path number
FORK25 sta ,Y+ Pass path to child
 decb COUNT Down
 bne FORK20 Branch if more
 bsr SETPRC Set up process
 bcs FORK40 Branch if error
 puls Y Retrieve parent process ptr
 sty D.PROC Make parent current process
 lda P$ID,X Get child id
 sta R$A,U Return to parent
 ldb P$CID,Y Get youngest child id
 sta P$CID,Y Set new child
 lda P$ID,Y Get parent id
 std P$PID,X Set parent & sibling ids
 ldb P$State,X Get child state
 andb #$FF-SysState Clear system state
 stb P$State,X Update child state
 OS9 F$AProc Activate child process
 rts
FORK40 pshs B Save error code
 OS9 F$EXIT Terminate child
 comb SET Carry
 puls B,X Retrieve error code & parent process ptr
 stx D.PROC Make parent current process
 rts

PRCFUL comb SET Carry
 ldb #E$PrcFul Err: process table full
 rts



*****
*
*  Subroutine Usrchn
*
* User Chain Routine
*
USRCHN bsr CHAIN Do chain
 bcs BADCHN Branch if error
 orcc #IRQMask+FIRQMask Set interrupt masks
 ldb P$State,X Clear system state
 andb #$FF-SysState
 stb P$State,X
USRC10 OS9 F$AProc Put process in active queue
 OS9 F$NProc Start next process



*****
*
*  Subroutine Syschn
*
* System Chain Routine
*
SYSCHN bsr CHAIN Do chain
 bcc USRC10 Branch if no error
BADCHN pshs B Save error code
 stb P$Signal,X Set error status
 ldb P$State,X Get process status
 orb #CONDEM Condem process
 stb P$State,X
 ldb #$FF Set high priority
 stb P$Prior,X
 comb
 puls B,PC



*****
*
* Subroutine Chain
*
* Execute Overlay
*
CHAIN pshs U Save register ptr
 ldx D.PROC Get process ptr
 ldu P$PModul,X Get primary module ptr
 OS9 F$Unlink
 ldu 0,S Retrieve register ptr
 bsr SETPRC Set up process
 puls U,PC Clean stack
 page
*****
*
*  Subroutine Setprc
*
* Set Up Process Descriptor
*
SETPRC ldx D.PROC Get process ptr
 pshs X,U Save process & register ptr
 ldd D.UsrSVC Get user service request
 std P$SWI,X Reset swi vector
 std P$SWI2,X Reset swi2 vector
 std P$SWI3,X Reset swi3 vector
 clra
 clrb
 sta P$Signal,X Clear signal
 std P$SigVec,X Clear signal vector ptr
 lda R$A,U Get type
 ldx R$X,U Get name ptr
 OS9 F$LINK
 bcc SETP10 Branch if found
 OS9 F$LOAD Try loading it
 bcs SETP50 Branch if not loadable
SETP10 ldy D.PROC Get process ptr
 stu P$PModul,Y Save primary module ptr
 cmpa #PRGRM+OBJCT is it program object?
 beq SETP15 branch if so
 cmpa #SYSTM+OBJCT is it system object?
 beq SETP15 branch if so
 comb set carry
 ldb #E$NEMod err: non-executable module
 bra SETP50
SETP15 leay 0,U Copy module ptr
 ldu 2,S Get register ptr
 stx R$X,U Return updated ptr
 lda R$B,U Get memory over-ride
 clrb
 cmpd M$Mem,Y Is it big enough?
 bcc SETP20
 ldd M$Mem,Y Get memory required
SETP20 addd #0 Req for zero data mem?
 bne SETP25 bra if not
 comb
 ldb #E$DelSP Error process must have at least one page mem
 bra SETP50
SETP25 OS9 F$MEM Mem to correct size
 bcs SETP50 Branch if no memory
 subd #R$SIZE Deduct stack room
 subd R$Y,U Deduct parameter count
 bcs BADPAR Branch if not available
 ldx R$U,U Get parameter beginning
 ldd R$Y,U Get parameter count
 pshs D Save parameter count
 beq SETP40 Branch if no parameters
 leax D,X Get parameter end ptr
SETP30 lda ,-X Get parameter byte
 sta ,-Y Pass it
 cmpx R$U,U Done?
 bhi SETP30 Branch if not
SETP40 ldx D.PROC Get process ptr
 sty R$X-R$SIZE,Y
 leay -R$SIZE,Y
 sty P$SP,X Set stack ptr
 lda P$ADDR,X Set beginning address
 clrb
 std R$U,Y
 sta R$DP,Y Get direct page ptr
 adda P$PagCnt,X Get end prt
 std R$Y,Y
 puls D Retrieve parameter byte count
 std R$D,Y Pass to process
 ldb #ENTIRE Set cc entire bit
 stb R$CC,Y
 ldu P$PModul,X Get module ptr
 ldd M$EXEC,U
 leau D,U Get module entry
 stu R$PC,Y Set new program counter
 clrb CLEAR Carry
BADPAR ldb #E$IForkP Err: illegal fork parameters
SETP50 puls X,U,PC
 page
*****
*
*  Subroutine Srqmem
*
* System Memory Request
*
SRQMEM ldd R$D,U Get byte count
 addd #$FF Round up to page
 clrb
 std R$D,U Return size to user
 ldx D.FMBM+2 Get end of bit map
 ldd #$1FF Set mask & bit number
 pshs D Save them
 bra SRQM20
SRQM10 dec 1,S Count page number down
 ldb 1,S Save it
SRQM15 lsl 0,S Shift mask
 bcc SRQM25 Branch if no byte change
 rol 0,S Move mask to low bit
SRQM20 leax -1,X Move to next map byte
 cmpx D.FMBM End of map?
 bcs SRQM30
SRQM25 lda 0,X Get map byte
 anda 0,S Get map bit
 bne SRQM10 Branch if allocated
 dec 1,S Count page number down
 subb 1,S Get number of free pages
 cmpb R$A,U Compare to requested number
 rora SAVE Carry
 addb 1,S Restore high page bound
 rola RESTORE Carry
 bcs SRQM15 Branch if not enough
 ldb 1,S Get page number
 clra
 incb
SRQM30 leas 2,S Return scratch
 bcs MEMFUL Branch if not enough
 ldx D.FMBM Get free memory ptr
 tfr D,Y Copy page number
 ldb R$A,U Get page count
 clra
 exg D,Y Switch page count & number
 bsr ALOCAT Allocate memory
 exg A,B Convert page number to address
 std R$U,U Return ptr to memory
SRQMXX clra CLEAR Carry
 rts

MEMFUL comb SET Carry
 ldb #E$MemFul Get error code
 rts
 page
*****
*
*  Subroutine Srtmem
*
* System Memory Return
*
SRTMEM ldd R$D,U Get byte count
 addd #$FF Round up to page
 tfr A,B Make page count
 clra
 tfr D,Y Copy page count
 ldd R$U,U Get address
 beq SRQMXX Branch if returning nothing
 tstb IS Address good?
 beq SRTM10 Branch if so
BADPAG comb SET Carry
 ldb #E$BPAddr
 rts
SRTM10 exg A,B Convert address to page number
 ldx D.FMBM Get free memory ptr
 bra DEALOC Deallocate memory
 page
*****
*
*  Subroutine Alocat
*
* Set Bits In Bit Map
*
* Input: D = Beginning Page Number
*        X = Bit Map Address
*        Y = Page Count
* Output: None
* Local: None
* Global: None
*
ABIT ldd R$D,U Get beginning bit number
 leau R$X,U
 pulu X,Y Get bit map addr & bit count
ALOCAT pshs D,X,Y Save registers
 bsr FNDBIT Adjust map ptr & get bit mask
 tsta TEST Mask
 pshs A Save mask
 bmi ALOC15 Branch if first bit of byte
 lda 0,X Get map byte
ALOC10 ora 0,S Set bit
 leay -1,Y Decrement page count
 beq ALOC35 Branch if done
 lsr 0,S Shift mask
 bcc ALOC10 Branch if more in this byte
 sta ,X+ Restore byte
ALOC15 tfr Y,D Copy page count
 sta 0,S Save msb
 lda #$FF Get eight pages worth
 bra ALOC25
ALOC20 sta ,X+ Get eight pages
ALOC25 subb #8 Are there eight left?
 bcc ALOC20 Branch if so
 dec 0,S Any msb left?
 bpl ALOC20 Branch if so
ALOC30 asla MAKE Final mask
 incb MOVE Count to zero
 bne ALOC30 Branch if not done
 ora 0,X Set final bits
ALOC35 sta 0,X Set byte
 clra CLEAR Carry
 leas 1,S Return scratch
 puls D,X,Y,PC
 page
*****
*
*  Subroutine Fndbit
*
* Make Page Number Into Ptr & Mask
*
* Input: D = Page Number
*        X = Map Beginning Address
* Output: A = Bit Mask
*         B = 0
*         X = Byte Address
* Local: None
* Global: None
*
FNDBIT pshs B Save lsb
 lsra PAGE/2
 rorb
 lsra PAGE/4
 rorb
 lsra PAGE/8
 rorb
 leax D,X Get byte address
 puls B Get lsb
 lda #$80 Get mask
 andb #7 Page modulo 8
 beq FNDB20 Branch if done
FNDB10 lsra SHIFT Mask
 decb
 bne FNDB10
FNDB20 rts
 page
*****
*
*  Subroutine Dealoc
*
* Deallocates Space In Bit Map
*
* Input: D = Beginning Page Number
*        X = Bit Map Address
*        Y = Page Count
* Output: None
* Local: None
* Global: None
*
DBIT ldd R$D,U Get beginning bit number
 leau R$X,U
 pulu X,Y Get bit map addr & bit count
DEALOC pshs D,X,Y Save registers
 bsr FNDBIT Adjust map ptr & get bit mask
 coma REVERSE Mask
 pshs A save it
 bpl DEAL10 branch if first bit of byte
 lda 0,X get map byte
DEAL05 anda 0,S Clear bit
 leay -1,Y Decrement page count
 beq DEAL30 Branch if done
 asr 0,S Shift mask
 bcs DEAL05 Branch if more
 sta ,X+ Store map byte
DEAL10 tfr Y,D Copy page count
 bra DEAL20
DEAL15 clr ,X+ Clear map byte
DEAL20 subd #8 Are there eight left?
 bhi DEAL15 Branch if so
 beq DEAL30 Branch if done
DEAL25 asla MAKE Final mask
 incb
 bne DEAL25
 coma REVERSE Mask
 anda 0,X Clear map bits
DEAL30 sta 0,X Store map byte
 clr ,S+ Clear carry & return scratch
 puls D,X,Y,PC
 page
*****
*
*  Subroutine Floblk
*
* Find Free Block Searching Up
*
* Same As Fhiblk
*
SBIT pshs U Save register ptr
 ldd R$D,U Get beginning bit number
 ldx R$X,U Get bit map ptr
 ldy R$Y,U Get bit count
 ldu R$U,U Get map end addr
 bsr FLOBLK Search bit map
 puls U Retrieve register ptr
 std R$D,U Return bit number
 sty R$Y,U return bits found
 rts

FLOBLK pshs D,X,Y,U Save registers
 pshs D,Y Copy beginning page number & size
 clr 8,S Clear size found
 clr 9,S
 tfr D,Y Copy beginning page number
 bsr FNDBIT Adjust map ptr & get bit mask
 pshs A Save mask
 bra FLOB20
FLOB10 leay 1,Y Move beginning bit number
 sty 5,S Save beginning block number
FLOB15 lsr 0,S Shift mask
 bcc FLOB25 Branch if mask okay
 ror 0,S Shift mask around end
 leax 1,X Move map ptr
FLOB20 cmpx 11,S End of map?
 bcc FLOB30 Branch if so
FLOB25 lda 0,X Get map byte
 anda 0,S Mask bit
 bne FLOB10 Branch if in use
 leay 1,Y Move page number
 tfr Y,D Copy page number
 subd 5,S Subtract beginning page number
 cmpd 3,S Block big enough?
 bcc FLOB35 Branch if so
 cmpd 9,S Biggest so far?
 bls FLOB15 Branch if not
 std 9,S Save size
 ldd 5,S Copy beginning page number
 std 1,S
 bra FLOB15
FLOB30 ldd 1,S Get beginning page number of largest
 std 5,S Return it
 coma SET Carry
 bra FLOB40
FLOB35 std 9,S Return size
FLOB40 leas 5,S Return scratch
 puls D,X,Y,U,PC
 page
***************
* Parse Path Name
*
* Passed:  (X)=Pathname Ptr
* Returns: (X)=Skipped Past Prefix '/'
*          (Y)=Ptr To 1St Delim In Pathname
*          (A)=Delimiter Character
*          (B)=Number Of Characters Found <=255
*           Cc=Set If No Characters Found
* Unaffects: U
*
PNAM ldx R$X,U Get string ptr
 bsr PRSNAM Call parse name
 std R$D,U Return byte & size
 bcs PNam.x branch if error
 stx R$X,U Return updated string ptr
PNam.x sty R$Y,U Return name end ptr
 rts

PRSNAM lda 0,X Get first char
 cmpa #'/ Slash?
 bne PRSNA1 ..no
 leax 1,X ..yes; skip it
PRSNA1 leay 0,X
 clrb
 lda ,Y+
 anda #$7F
 bsr ALPHA 1st character must be alphabetic
 bcs PRSNA4 Branch if bad name
PRSNA2 incb INCREMENT Character count
 lda -1,Y End of name (high bit set)?
 bmi PRSNA3 ..yes; quit
 lda ,Y+ Get next character
 anda #$7F Strip high order bit
 bsr ALFNUM Alphanumeric?
 bcc PRSNA2 ..yes; count it
 lda ,-Y Backup to unknown
PRSNA3 andcc #^CARRY clear carry
 rts RETURN (carry clear)

PRSNA4 cmpa #', Comma (skip if so)?
 bne PRSNA6 ..no
PRSNA5 lda ,Y+ Get next character
PRSNA6 cmpa #$20 Space?
 beq PRSNA5 ..yes; skip
 lda ,-Y Backup to non-delim char
 comb (NAME Not found)
 ldb #E$BNam 
 rts RETURN Carry set



* Check For Alphanumeric Character
*
* Passed:  (A)=Char
* Returns:  Cc=Set If Not Alphanumeric
* Destroys None
*
ALFNUM cmpa #'. period?
 beq RETCC branch if so
 cmpa #'0 Below zero?
 blo RETCS ..yes; return carry set
 cmpa #'9 Numeric?
 bls RETCC ..yes
 cmpa #'_ Underscore?
 beq RETCC ..yes
ALPHA cmpa #'A
 blo RETCS
 cmpa #'Z Upper case alphabetic?
 bls RETCC ..yes
 cmpa #$61 Below lower case a?
 blo RETCS ..yes
 cmpa #$7A Lower case?
 bls RETCC ..yes
RETCS orcc #CARRY Set carry
 rts



* Compare Pathname With Module Name
*
* Passed:  (X)=Pathname
*          (Y)=Module Name (High Bit Set Delim)
*          (B)=Length Of Pathname
* Returns:  Cc=Set If Names Not Equal
*
CNAM ldb R$B,U Get size
 leau R$X,U
 pulu X,Y Get string ptrs
CHKNAM pshs D,X,Y Save registers
CHKN10 lda ,Y+ Get (next) char of module name
 bmi CHKN20 Branch if last module char
 decb DECREMENT Char count
 beq RETCS1 Branch if last character
 eora ,X+ Equal pathname char?
 anda #$FF-$20 Match upper/lower case
 beq CHKN10 ..yes; repeat
RETCS1 comb Set carry
 puls D,X,Y,PC
CHKN20 decb LAST Char of pathname?
 bne RETCS1 Branch if not
 eora 0,X Does last one match?
 anda #$FF-$A0 Match upper/lower & high order bit
 bne RETCS1 ..no; return carry set
 puls D,X,Y Restore regs
RETCC andcc #$FF-CARRY Clear carry
 rts
 page
*****
*
*  Subroutine Ssvc
*
* Set Entries In Service Routine Dispatch Tables
*
SSVC ldy R$Y,U Get table address
 bra SETSVC

SETS10 tfr B,A copy routine offset
 anda #$7F mask upper bit
 cmpa #$7F Is routine Ioman?
 beq SETS30 Bra if so
 cmpa #SVCTSZ/2 Is routine offset legal?
 bcs SETS30 Bra if so
 comb set carry
 ldb #E$ISWI return error
 rts

SETS30 aslb MAKE Table offset
 ldu D.SysDis Get system service table
 leau B,U Get entry ptr
 ldd ,Y++ Get table relative offset
 leax D,Y Get routine address
 stx 0,U Put in system routine table
 bcs SETSVC Branch if system only
 stx SVCTSZ+2,U Put in user routine table
SETSVC ldb ,Y+ Get next routine offset
 cmpb #$80 End of table code?
 bne SETS10 Branch if not
 rts
 page

 ifne (CPUType-GIMIX)*(CPUType-EXORSR)
 opt l
 endc

 ifeq CPUType-GIMIX
*
* Dynamic Address Translator Initialization
*
DATINT clr $E231 Clear m58167 interrupts
 ldx #$FFF0
 ldb #$D
DAT10 stb B,X Init dat register
 decb Next Dat mask
 bpl DAT10 branch if more
 ldb #$FE Get extended rom address
 stb $E,X Set dat image
 incb
 stb $F,X Set dat image
 lbra COLD
 endc

 ifeq CPUType-SWTC
*
* Dynamic Address Translator Initialization
*
DATINT ldx #$FFF0 Get dat address
 ldb #$0F Get dat mask
DAT10 stb ,X+ Init dat register
 decb Change Dat mask
 bpl DAT10 Branch if mo'
 lbra COLD dat stuff done
 endc

 ifeq CPUType-SSB
*
* Dynamic Address Translator Initialization
*
DATINT clra Set Task number
 ldx #$FFF0 Get dat address
 sta -1,X Set dat task register
 ldb #$D
DAT10 stb B,X Init dat register
 decb Next Dat mask
 bpl DAT10 branch if more
 ldb #$FE Get extended rom address
 stb $E,X Set dat image
 incb
 stb $F,X Set dat image
 sta $F711 Clear clock interrupts
 lbra COLD
 endc

 ifeq CPUType-S09
*
* Dynamic Address Translator Initialization
*
DATINT ldx #$FFF0 Get dat ptr
 ldb #$10 First dat mask
DAT10 lda #4 Init four blocks per board segment
DAT20 decb NEXT Mask
 stb ,X+ Init dat register
 deca COUNT Down
 bne DAT20 Branch if more
 addb #$14 Next board segment
 cmpx #$FFF0 End of dat?
 bcc DAT10 Branch if not
 inca
 clrb D now = $0100 set upper 8K to high addresses
 std $FFFE
 lbra COLD
 endc

 ifeq CPUType-HELIX
*
* Dynamic Address Translator Initialization
*
DATINT ldx #$FFF0
 ldb #$D
DAT10 stb B,X Init dat register
 decb Next Dat mask
 bpl DAT10 branch if more
 ldb #$FE Get extended rom address
 stb $E,X Set dat image
 incb
 stb $F,X Set dat image
 lbra COLD
 endc

 emod
OS9End equ *
 page
 ifeq CPUType-CMS9619
*****
* CMS 9619 CPU patch
*
* This CPU uses the area between $FF80 and $FFDF for I/O
*
* This patch puts garbage in the ROM at these addresses
*
 fcc /9999999999999999/
 fcc /9999999999999999/
 fcc /9999999999999999/
 fcc /9999999999999999/
 fcc /9999999999999999/
 fcc /9999999999999999/
 endc
*****
*
* Interrupt Vector Package
*
* Generate Rtses to $FFE0
*
 ifle *-$7D0
 fcc /9999999999999999/
 endc
 ifle *-$7D0
 fcc /9999999999999999/
 endc
 ifle *-$7D0
 fcc /9999999999999999/
 endc
 ifle *-$7D0
 fcc /9999999999999999/
 endc
 ifle *-$7D0
 fcc /9999999999999999/
 endc
 ifle *-$7D0
 fcc /9999999999999999/
 endc
 ifle *-$7D0
 fcc /9999999999999999/
 endc
 ifle *-$7D0
 fcc /9999999999999999/
 endc
 ifle *-$7D8
 fcc /99999999/
 endc
 ifle *-$7DC
 fcc /9999/
 endc
 ifle *-$7DE
 fcc /99/
 endc
 ifle *-$7DF
 fcc /9/
 endc

*
* Os-9 System Entries
*
 fdb TICK+$FFE0-* Clock tick handler
SYSVEC fdb SWI3HN+$FFE2-* Swi3 handler
 fdb SWI2HN+$FFE4-* Swi2 handler
 fdb FIRQHN+$FFE6-* Fast irq handler
 fdb IRQHN+$FFE8-* Irq handler
 fdb SWIHN+$FFEA-* Swi handler
 fdb NMIHN+$FFEC-* Nmi handler
 fdb 0 Reserved
* Actual Vector Entries
 fdb 0 Reserved
 fdb SWI3RQ+$FFF2-* Swi3
 fdb SWI2RQ+$FFF4-* Swi2
 fdb FIRQ+$FFF6-* Firq
 fdb IRQ+$FFF8-* Irq
 fdb SWIRQ+$FFFA-* Swi
 fdb NMI+$FFFC-* Nmi

 ifeq (CPUType-MM19)*(CPUType-PERCOM)*(CPUType-CMS9609)*(CPUType-ELEKTRA)*(CPUType-DIGALOG)*(CPUType-SAT96)
 fdb COLD+$FFFE-* Restart
 else
 ifeq (CPUType-EXORSR)*(CPUType-CMS9619)
 fdb COLD+$FFFE-*
 else
 fdb DATINT+$FFFE-* Dynamic address translator initialization
 endc
 endc

ROMEnd equ *


 end
